#include "device_app.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <linux/fs.h>
#include <errno.h>

#define DEVICE_NAME "device_driver"
#define BUFFER_SIZE 1024  // 定义缓冲区大小

// 打印用法信息
void print_usage() {
    printf("Usage:\n");
    printf("  -o  : Open device\n");
    printf("  -r  : Read from device\n");
    printf("  -w  : Write to device\n");
    printf("  -c  : Close device\n");
    printf("  -s  : Set data to device (e.g., -s \"Hello, Device!\")\n");
    printf("  -g  : Get data from device\n");
}

// 根据主设备号动态生成设备路径
char *get_device_path(int major_num) {
    char *device_path = malloc(64);  // 为设备路径分配内存
    if (device_path == NULL) {
        perror("Failed to allocate memory for device path");
        exit(EXIT_FAILURE);
    }

    snprintf(device_path, 64, "/dev/%s", DEVICE_NAME);  // 生成设备路径
    return device_path;
}

// 确保传递给 ioct 的数据大小为 1024 字节
void prepare_ioctl_data(char *input_data, char *buffer) {
    // 清空缓冲区
    memset(buffer, 0, BUFFER_SIZE);

    // 将输入数据复制到缓冲区，保证不超过 1024 字节
    strncpy(buffer, input_data, BUFFER_SIZE - 1);
}

int app(int argc, char *argv[]) {
    int fd;
    char buffer[BUFFER_SIZE];
    ssize_t len;
    char *device_path;

    if (argc < 2) {
        print_usage();
        return 1;
    }

    // 动态获取设备路径
    device_path = get_device_path(0);  // 使用主设备号 0，表示通过主设备号自动构建路径

    if (strcmp(argv[1], "-o") == 0) {
        fd = open(device_path, O_RDWR);
        if (fd == -1) {
            perror("Failed to open device");
            free(device_path);
            return 1;
        }
        printf("Device opened successfully\n");

    } else if (strcmp(argv[1], "-r") == 0) {
        fd = open(device_path, O_RDWR);
        if (fd == -1) {
            perror("Failed to open device for reading");
            free(device_path);
            return 1;
        }

        len = read(fd, buffer, sizeof(buffer));
        if (len == -1) {
            perror("Failed to read from device");
        } else {
            printf("Read %zd bytes: %s\n", len, buffer);
        }

    } else if (strcmp(argv[1], "-w") == 0) {
        if (argc < 3) {
            print_usage();
            free(device_path);
            return 1;
        }

        fd = open(device_path, O_RDWR);
        if (fd == -1) {
            perror("Failed to open device for writing");
            free(device_path);
            return 1;
        }

        len = write(fd, argv[2], strlen(argv[2]));
        if (len == -1) {
            perror("Failed to write to device");
        } else {
            printf("Written %zd bytes: %s\n", len, argv[2]);
        }

    } else if (strcmp(argv[1], "-s") == 0) {
        if (argc < 3) {
            print_usage();
            free(device_path);
            return 1;
        }

        fd = open(device_path, O_RDWR);
        if (fd == -1) {
            perror("Failed to open device for setting data");
            free(device_path);
            return 1;
        }

        // 确保传递给 IOCTL 的数据大小为 1024
        prepare_ioctl_data(argv[2], buffer);

        // IOCTL 设置数据
        if (ioctl(fd, IOCTL_SET_DATA, buffer) == -1) {
            perror("IOCTL Set Data failed");
            printf("errno: %d\n", errno);
        } else {
            printf("Data set to device: %s\n", buffer);
        }

    } else if (strcmp(argv[1], "-g") == 0) {
        fd = open(device_path, O_RDWR);
        if (fd == -1) {
            perror("Failed to open device for getting data");
            free(device_path);
            return 1;
        }

        // IOCTL 获取数据
        if (ioctl(fd, IOCTL_GET_DATA, buffer) == -1) {
            perror("IOCTL Get Data failed");
        } else {
            printf("Data from device: %s\n", buffer);
        }

    } else if (strcmp(argv[1], "-c") == 0) {
        fd = open(device_path, O_RDWR);
        if (fd == -1) {
            perror("Failed to open device for closing");
            free(device_path);
            return 1;
        }
        close(fd);
        printf("Device closed\n");

    } else {
        print_usage();
        free(device_path);
        return 1;
    }

    free(device_path);  // 释放分配的内存
    return 0;
}
